package com.example.dmallOrder.common.dmall.util;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Map;
import java.util.TreeMap;

/**
 *
 * 生成签名工具类
 *
 * @author:xxx
 * @date: 2023/3/18
 */
public  class SignUtil2 {


    /**
     * 将请求数据进行签名 用于API请求
     * @param appKey
     * @param secret
     * @param token
     * @param signMethod
     * @param timestamp
     * @param dmallParams
     * @return
     */
    public static String generateSignature(String appKey, String secret, String token, String signMethod, String timestamp, Map<String,Object> dmallParams) {
        //将所有参数进行按照字母顺序排序
        TreeMap<String,Object> params = new TreeMap<>();
        params.putAll(dmallParams);
        params.put("app-key", appKey);
        params.put("token", token);
        params.put("sign-method", signMethod);
        params.put("timestamp", timestamp);

        //将排序好的参数名和参数值拼装在一起并转大写
        String stringToSign = buildSignString(params);

        //使用MD5/HmacSHA256加密，并进行Base64编码获取字符串
        try {
            if (signMethod.equalsIgnoreCase("HmacSHA256")) {
                return hamcThenBase64(stringToSign.getBytes(StandardCharsets.UTF_8), secret);
            } else {
                return md5ThenBase64(stringToSign);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 根据数据生成签名 -- 用于获取token
     * @param appKey
     * @param signMethod
     * @param timestamp
     * @param dmallParams
     * @return
     */
    public static String generateTokenSignature(String appKey, String code, String timestamp, String signMethod,String secret , Map<String,Object> dmallParams) {
        //将所有参数进行按照字母顺序排序
        TreeMap<String, Object> params = new TreeMap<>();
        params.putAll(dmallParams);
        params.put("appKey", appKey);
        params.put("code", code);
        params.put("timestamp", timestamp);

        //将排序好的参数名和参数值拼装在一起并转大写
        String stringToSign = buildSignString(params);

        //使用MD5/HmacSHA256加密，并进行Base64编码获取字符串
        try {
            if (signMethod.equalsIgnoreCase("HmacSHA256")) {
                return hamcThenBase64(stringToSign.getBytes(StandardCharsets.UTF_8), secret);
            } else {
                return md5ThenBase64(stringToSign);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }






    public static String buildSignString(TreeMap<String,Object> params) {
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String,Object> entry : params.entrySet()) {
            //过滤掉null值
            if (entry.getKey() != null && entry.getValue() != null) {
                sb.append(entry.getKey()).append(entry.getValue());
            }
        }
        return sb.toString().toUpperCase();
    }

    /**
     * 先进行MD5摘要再进行Base64编码获取摘要字符串
     */
    public static String md5ThenBase64(String stringToSign) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] bytes = md.digest(stringToSign.getBytes(StandardCharsets.UTF_8));

            StringBuilder sign = new StringBuilder();
            for (byte aByte : bytes) {
                String hex = Integer.toHexString(aByte & 0xFF);
                if (hex.length() == 1) {
                    sign.append("0");
                }
                sign.append(hex.toUpperCase());
            }

            return Base64.getEncoder().encodeToString(sign.toString().getBytes(StandardCharsets.UTF_8));
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }

    public static String hamcThenBase64(byte[] bytes, String secret) throws Exception {
        Mac hmacSha256 = Mac.getInstance("HmacSHA256");
        byte[] keyBytes = secret.getBytes(StandardCharsets.UTF_8);
        hmacSha256.init(new SecretKeySpec(keyBytes, "HmacSHA256"));
        byte[] bs = hmacSha256.doFinal(bytes);
        return Base64.getEncoder().encodeToString(bs);
    }
}
